import json
import logging
import re

from pypinyin import pinyin, Style

from blls.base_bll import BaseBLL
from config import FUNCTION_ID, FUNCTION, REDIS_HOST, REDIS_PORT, REDIS_DATABASE, REDIS_KEY
from dtos.result import Result
from enumobjects.file_num import ErrorEnum
from enumobjects.general_enum import YesOrNoEnum
from utils.common_util import CommonUtil
from utils.external_api_check import ExternalApiCheck
from utils.guid_util import GUIDUtil
from utils.upload_util import UploadUtil
from models.standardized_models.application_model import Application
from models.file_models.file_model import File
from lib.redis_wrapper import  RedisWrapper


class FileUploadBLL(BaseBLL):

    def _image_path_check(self, files):
        try:
            if not files:
                return Result.error_result(
                    message=ErrorEnum.to_frontend_desc(ErrorEnum.FILE_ERROR.value),
                    code=ErrorEnum.FILE_ERROR.value
                )
            return Result.success_result()
        except Exception as ex:
            _err_message = "%s 检查参数时出现异常，原因；%s" % (files, str(ex))
            logging.info(_err_message)
            return Result.error_result(
                code=ErrorEnum.SERVER_ERROR.value,
                message=_err_message
            )

    def check_params_info(self, files):
        res = self._image_path_check(files)
        if not res.is_success:
            return res
        return Result.success_result()

    def get_application(self, app_id):
        application_obj = self.standardized_session.query(Application).filter(
            Application.is_delete == YesOrNoEnum.NO.value,
            Application.is_disable == YesOrNoEnum.NO.value,
            Application.app_id == app_id
        ).first()
        return application_obj

    def check_sign(self, files, api_secret, function_ids_str, **data):
        function_ids = function_ids_str.split(",")
        if FUNCTION_ID not in function_ids:
            return Result.error_result(message="该应用无法访问该服务", code=402)
        image = files['file'][0]
        filename, content_type, body = image['filename'], image['content_type'], image['body']
        data['file'] = CommonUtil.get_md5_bytes_value(body)
        check_res = ExternalApiCheck(api_secret=api_secret).check(**data)
        return check_res

    def get_app_version(self, app_id, chinese_scene):
        clean_scene = re.sub(r'[^\u4e00-\u9fa5]', '', chinese_scene)
        # 转换为拼音首字母
        initials = [p[0].upper() for p in pinyin(clean_scene, style=Style.FIRST_LETTER)]
        base_code = ''.join(initials)[:5]
        file_obj = self.db_session.query(File).filter(
            File.is_delete == YesOrNoEnum.NO.value,
            File.app_id == app_id,
            File.scene == chinese_scene
        ).order_by(File.id.desc()).first()
        if not file_obj:
            new_version = '_'.join([base_code, app_id, '1'])
        else:
            last_version = file_obj.versions
            last_version = int(last_version.split('_')[-1])
            new_version = '_'.join([base_code, app_id, str(last_version + 1)])
        return new_version

    def file_upload(self, files, file_size, **data):
        check_params_info_res = self.check_params_info(files)
        if not check_params_info_res.is_success:
            return check_params_info_res
        app_id, scene = data['app_id'], data['scene']
        application_obj = self.get_application(app_id)
        if not application_obj:
            return Result.error_result(message="未根据app_id找到对应的应用")
        check_sign_res = self.check_sign(files, application_obj.server_secret,
                                         application_obj.function_ids_str, **data)
        if not check_sign_res.is_success:
            return check_sign_res
        upload_res = UploadUtil().image_upload(files, ["file"], "file")
        if not upload_res.is_success:
            return upload_res
        file_path = upload_res.data.get("file").get('file_path')
        if not file_path:
            return Result.error_result(message="上传的文件错误。", code=ErrorEnum.FILE_ERROR.value)
        file_name = upload_res.data.get("file").get('file_name')
        self.db_session.begin(subtransactions=True)
        try:
            new_version = self.get_app_version(app_id, scene)
            file_obj = File(
                guid=str(GUIDUtil.generate()),
                app_id=app_id,
                versions=new_version,
                file_name=file_name,
                file_path=file_path,
                function=FUNCTION,
                scene=scene,
                create_time=CommonUtil.get_timestamp()
            )
            self.db_session.add(file_obj)
            self.db_session.commit()
        except Exception as ex:
            message = "添加文件失败，原因是：%s" % str(ex)
            logging.info(message)
            self.db_session.rollback()
            return Result.error_result(message="上传文件失败", code=500)
        # 推送任务到Redis
        task_data = {
            'file_path': file_path,
            'version': new_version,
            'app_id': app_id,
            'scene': scene
        }
        # 修改此处：使用 RedisWrapper 的静态方法
        RedisWrapper.lpush(REDIS_KEY, json.dumps(task_data))

        return Result.success_result(message="上传文件成功", data={
            'file_path': file_path,
            'version': new_version
        })

    def health(self):
        logging.info("健康检测")
        return Result.success_result()